package com.colin.userservice.config;

import com.aliyun.dypnsapi20170525.models.SendSmsVerifyCodeRequest;
import com.aliyun.dypnsapi20170525.models.SendSmsVerifyCodeResponse;
import com.aliyun.teautil.models.RuntimeOptions;
import com.aliyuncs.exceptions.ClientException;
import com.colin.response.R;
import com.colin.response.RCM;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.concurrent.TimeUnit;

@Slf4j
@Configuration
public class AliyunSMSConfig {

    @Value("${aliyun.sms.access-key-id}")
    private String accessKeyId;

    @Value("${aliyun.sms.access-key-secret}")
    private String accessKeySecret;

    @Value("${aliyun.sms.sign-name}")
    private String signName;

    @Value("${aliyun.sms.template-code}")
    private String templateCode;

    @Value("${aliyun.sms.region-id}")
    private String regionId;

    @Value("${aliyun.sms.endpoint}")
    private String endpoint;

    @Value("${aliyun.sms.connect-timeout}")
    private Integer connectTimeout;

    @Value("${aliyun.sms.read-timeout}")
    private Integer readTimeout;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;


    private static final String CODE_PREFIX = "sms:code:";
    private static final long EXPIRE_TIME = 5 * 60; // 5分钟过期


    @Bean
    public com.aliyun.dypnsapi20170525.Client aliyunSMSClient() {
        if (accessKeyId == null || accessKeySecret == null || signName == null || templateCode == null || regionId == null) {
            log.error("参数未配置全");
            throw new RuntimeException("参数未配置全");
        }
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config();
        config.setAccessKeyId(accessKeyId);
        config.setAccessKeySecret(accessKeySecret);
        config.setEndpoint(endpoint);
        com.aliyun.credentials.Client credentialsClient = new com.aliyun.credentials.Client();
        config.setCredential(credentialsClient);
        try {
            return new com.aliyun.dypnsapi20170525.Client(config);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }



    /**
     * 发送短信验证码
     */
    public R<String> sendVerificationCode(String phoneNum) {
        // 3. 生成随机验证码
        String code = generateRandomCode();

        // 4. 发送短信
        try {
            boolean sendResult = sendSms(phoneNum, code);
            if (sendResult) {
                // 发送成功，保存到Redis
                saveCodeToRedis(phoneNum, code);
                return R.ok("验证码发送成功");
            } else {
                return R.error(RCM.USER_MESSAGE_ERROR);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return R.error(RCM.USER_MESSAGE_EXCEPTION);
        }
    }

    /**
     * 实际发送短信的方法
     */
    private boolean sendSms(String phoneNumber, String code) {
        try {
            SendSmsVerifyCodeRequest request = new SendSmsVerifyCodeRequest()
                    .setSignName(signName)
                    .setTemplateCode(templateCode)
                    .setPhoneNumber(phoneNumber)
                    .setTemplateParam("{\"code\":\"" + code + "\",\"min\":\"5\"}");

            RuntimeOptions options = new RuntimeOptions();
            options.setConnectTimeout(connectTimeout);
            options.setReadTimeout(readTimeout);

            log.info("开始发送短信验证码：phoneNum={},code={}", phoneNumber, code);
            SendSmsVerifyCodeResponse response = aliyunSMSClient().sendSmsVerifyCode(request);

            if (!"OK".equals(response.getBody().getCode())) {
                log.error("短信验证码发送失败：code={}", response.getBody().getCode());
                throw new RuntimeException("验证码发送失败");
            }else{
                log.info("短信验证码发送成功");
                return true;
            }
        } catch (ClientException e) {
            log.error("短信客户端异常：phoneNum={},code={}", phoneNumber, code, e);
            throw new RuntimeException("短信发送客户端异常", e);
        } catch (Exception e) {
            log.error("短信发送异常：phoneNum={},code={}", phoneNumber, code, e);
            throw new RuntimeException("短信发送异常", e);
        }
    }

    /**
     * 生成6位随机数字验证码
     */
    private String generateRandomCode() {
        return String.valueOf((int)((Math.random() * 9 + 1) * 100000));
    }

    /**
     * 保存验证码到Redis
     */
    private void saveCodeToRedis(String phoneNum, String code) {
        String key = CODE_PREFIX + phoneNum;
        redisTemplate.opsForValue().set(key, code, EXPIRE_TIME, TimeUnit.SECONDS);

        // 设置发送频率限制：1分钟内只能发送1次
        String limitKey = "sms:limit:" + phoneNum;
        redisTemplate.opsForValue().set(limitKey, "1", 1, TimeUnit.MINUTES);
    }

    /**
     * 检查发送频率限制
     */
    private boolean checkRateLimit(String phoneNum) {
        String limitKey = "sms:limit:" + phoneNum;
        return redisTemplate.opsForValue().get(limitKey) == null;
    }

    /**
     * 验证用户输入的验证码
     */
    public R<String> verifyCode(String phoneNum, String inputCode) {
        String key = CODE_PREFIX + phoneNum;
        String storedCode = redisTemplate.opsForValue().get(key);

        if (storedCode == null) {
            return R.error(null);
        }

        if (!storedCode.equals(inputCode)) {
            return R.error(null);
        }

        // 验证成功，删除验证码（防止重复使用）
        redisTemplate.delete(key);
        return R.ok("验证成功");
    }

    /**
     * 根据手机号从Redis中获取验证码
     * @param phoneNum 手机号
     * @return 验证码，如果不存在或已过期则返回null
     */
    public String getVerificationCodeFromRedis(String phoneNum) {
        String key = CODE_PREFIX + phoneNum;
        return redisTemplate.opsForValue().get(key);
    }

}
